import {
  _decorator,
  Component,
  Node,
  Scene,
  Vec3,
  Color,
  Label,
  Layers,
  find,
} from 'cc';
import { Clock } from '../core/Clock';
import { emit } from '../core/EventBus';
import { SceneInstaller } from '../installers/SceneInstaller';
import AutoSpawner from '../debug/AutoSpawner';
import applyTestLoadout from '../debug/DefaultLoadout';
import { DEBUG_FORCE_SPAWN_DEMO, DEBUG_TEST_LOADOUT, DEBUG_REPAIR_MISSING_SCRIPTS, TICK_RATES } from '../shared';
import { ENABLE_W1, ENABLE_W2 } from '../shared/DebugFlags';
import { enableAssetGuard } from '../debug/AssetGuard';
import RepairMissingScripts from '../tools/RepairMissingScripts';
import { bootstrapWorld } from '../world/WorldRoot';
import ChunkManager, { bootstrapChunkManager } from '../world/ChunkManager';
import TileOccluder, { bootstrapTileOccluder } from '../world/TileOccluder';
import MiniMap, { bootstrapMiniMap } from '../hud/MiniMap';
import ExtractSpawner from '../gameplay/ExtractSpawner';
import { ExtractPoint } from '../gameplay/ExtractPoint';
import { EnemyDummy } from '../gameplay/EnemyDummy';
import { bootstrapCameraFollow } from '../camera/CameraFollow';

const { ccclass, property } = _decorator;

@ccclass('BootScene')
export class BootScene extends Component {
  @property
  public autoEmitMatchStart = true;

  private clock: Clock | null = null;

  onLoad() {
    console.log('[BOOT] onLoad');
    try {
      try {
        enableAssetGuard(true);
      } catch {}

      if (DEBUG_REPAIR_MISSING_SCRIPTS) {
        this.node.getComponent(RepairMissingScripts) ?? this.node.addComponent(RepairMissingScripts);
      }

      const g = globalThis as any;
      if (g.__BOOT_INIT__) {
        console.log('[BOOT] already initialized');
        return;
      }
      g.__BOOT_INIT__ = true;

      let player: Node | null = null;
      if (ENABLE_W1) {
        this.clock = this.node.getComponent(Clock) ?? this.node.addComponent(Clock);
        player = SceneInstaller.ensure(this.node.scene);
        if (player && DEBUG_TEST_LOADOUT) {
          applyTestLoadout(player);
        }
        if (this.autoEmitMatchStart) {
          emit('match/start', { seed: Date.now(), map: 'demo' });
        }
        if (DEBUG_FORCE_SPAWN_DEMO) {
          try {
            this.node.addComponent(AutoSpawner);
          } catch (err) {
            console.error('[BOOT-ERROR]', err);
          }
        }
        console.log('[BOOT] W1 installed, player=', player?.uuid ?? 'null');
      } else {
        console.log('[BOOT] W1 disabled via flag');
      }

      if (ENABLE_W2) {
        this.initW2Systems(player);
      } else {
        console.log('[BOOT] W2 skipped via flag');
      }
    } catch (err) {
      console.error('[BOOT-ERROR]', err);
    }
  }

  private initW2Systems(player: Node | null) {
    try {
      const scene = this.node.scene as Scene | null;
      if (!scene) {
        console.warn('[BOOT] W2 aborted: scene unavailable');
        return;
      }
      const root = scene as unknown as Node;
      const canvas = root.getChildByName('Canvas');
      if (!canvas) {
        console.warn('[BOOT] W2 aborted: Canvas missing');
        return;
      }

      const { world: worldLayer, ui: uiLayer } = bootstrapWorld(canvas);

      const targetPlayer = player ?? worldLayer.getChildByName('Player') ?? null;
      if (!targetPlayer) {
        console.warn('[BOOT] W2 warning: player node missing');
      }

      const clock = targetPlayer?.getComponent(Clock) ?? this.clock ?? null;

      const hudNode = uiLayer.getChildByName('HUD') ?? canvas.getChildByName('HUD');
      if (hudNode && hudNode.parent !== uiLayer) {
        hudNode.removeFromParent();
        uiLayer.addChild(hudNode);
      }

      const miniNode = uiLayer.getChildByName('MiniMap') ?? new Node('MiniMap');
      if (!miniNode.parent) {
        uiLayer.addChild(miniNode);
      }
      const miniMap = miniNode.getComponent(MiniMap) ?? miniNode.addComponent(MiniMap);

      const occluder = worldLayer.getComponent(TileOccluder) ?? worldLayer.addComponent(TileOccluder);
      bootstrapTileOccluder(occluder);
      const chunkManager = worldLayer.getComponent(ChunkManager) ?? worldLayer.addComponent(ChunkManager);
      bootstrapChunkManager(chunkManager);
      const camNode = find('Canvas/Camera');
      const follow = camNode?.getComponent(CameraFollow) ?? camNode?.addComponent(CameraFollow);
      if (follow && targetPlayer) {
        bootstrapCameraFollow(follow, targetPlayer);
      }

      if (clock && targetPlayer) {
        clock.unregister?.('chunk-ensure');
        clock.register('chunk-ensure', TICK_RATES.navigation, () => {
          chunkManager.ensureAround(targetPlayer.worldPosition, 1);
        });
      }

      const spawner = worldLayer.getComponent(ExtractSpawner) ?? worldLayer.addComponent(ExtractSpawner);
      spawner.worldLayer = worldLayer;
      spawner.player = targetPlayer;

      const existingExtracts = [...worldLayer.children].filter((n) => !!n.getComponent(ExtractPoint));
      if (existingExtracts.length > 0) {
        for (const node of existingExtracts) {
          spawner.registerExisting(node, 40, 'fixed', true);
        }
      } else {
        spawner.spawnFixed(new Vec3(640, 0, 0));
      }
      spawner.spawnHidden(true);

      if (targetPlayer) {
        bootstrapMiniMap(miniMap, {
          player: targetPlayer,
          chunkManager,
          extractSpawner: spawner,
        });
      } else {
        bootstrapMiniMap(miniMap, {
          player: null,
          chunkManager,
          extractSpawner: spawner,
        });
      }

      if (!DEBUG_FORCE_SPAWN_DEMO) {
        this.spawnDemoEnemies(worldLayer);
      }

      console.log('[BOOT] W2 init done');
    } catch (err) {
      console.error('[W2-ERROR]', err);
    }
  }

  private spawnDemoEnemies(worldLayer: Node) {
    const existing = [...worldLayer.children].some((n) => /^Enemy_/.test(n.name));
    if (existing) return;
    const positions = [
      new Vec3(6, 0, 4),
      new Vec3(-5, 0, 7),
      new Vec3(2, 0, -6),
      new Vec3(8, 0, -3),
    ];
    const count = 3 + Math.floor(Math.random() * 3);
    for (let i = 0; i < count; i++) {
      const node = new Node(`Enemy_${i}`);
      const pos = positions[i % positions.length];
      node.setWorldPosition(pos);
      node.layer = Layers.Enum.DEFAULT;
      const enemy = node.addComponent(EnemyDummy);
      enemy.threatLevel = 0.3 + i * 0.15;
      enemy.maxHealth = 80 + i * 20;
      const label = node.addComponent(Label);
      label.string = 'Enemy';
      label.color = Color.RED;
      worldLayer.addChild(node);
    }
  }
}

export default BootScene;
